﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Configuration;
using Microsoft.Office.Interop.Word;

namespace Tikarabbit
{
    /// <summary>
    /// This class plays the role of Object Pool pattern.
    /// Instance of this class manage Reusable objects 
    /// for use by Client objects. Usually.
    /// It is desirable to keep all Reusable objects that 
    /// are not currently in use in the same object pool 
    /// so that they can be managed by one coherent policy. 
    /// To achieve this, the ReusablePool class is designed 
    /// to be a singleton class. 
    /// Its constructor(s) are private, which forces 
    /// other classes to call its Instance method to 
    /// get the one instance of the ReusablePool class.
    /// </summary>
    public class OfficeObjectPool<T> where T : class
    {

        # region Static members
        private static readonly object _locker = new object();

        static OfficeObjectPool<T> poolInstance = null;

        /// <summary>
        /// Only way of creating the OfficeObjectPool instance
        /// </summary>
        public static OfficeObjectPool<T> Instance
        {

            get
            {
                lock (_locker)
                {
                    if (poolInstance == null)
                    {
                        poolInstance = new OfficeObjectPool<T>();
                    }
                    return poolInstance;
                }
            }
        }
        #endregion

        # region Private members
        Queue<T> myQ = new Queue<T>();
        #endregion

        #region Public properties
        public int Count
        {
            get { return myQ.Count; }
        }
        #endregion

        # region Construction

        /// <summary>
        /// No access to clients
        /// </summary>
        /// <param name="InitialSize"></param>
        private OfficeObjectPool()
        {

            String wordPoolMaxSize = ConfigurationSettings.AppSettings["WordPoolMax"];
            String wordPoolInitialSize = ConfigurationSettings.AppSettings["WordPoolInitialSize"];
            int iWordPoolMaxSize = 2;
            int iWordPoolInitialSize = 2;
            if (wordPoolMaxSize != null)
            {
                try
                {
                    iWordPoolMaxSize = Int32.Parse(wordPoolMaxSize);
                }
                catch (Exception)
                {
                }
            }
            if (wordPoolInitialSize != null)
            {
                try
                {
                    iWordPoolInitialSize = Int32.Parse(wordPoolInitialSize);
                }
                catch (Exception)
                {
                }
            }
            //oWord = new Application[iWordPoolSize];
            while (iWordPoolInitialSize > 0)
            {

                // http://ralch.wordpress.com/2008/11/22/the-singleton-pattern-how-to-make-it-reusable/
                // How to make a new instance. But here is confusing how C# really works. 
                //T t = Activator.CreateInstance<T>(); //(typeof(T), true) as T;

                // Create initial objects in the pool
                T t = null;
                if (typeof(T)  == typeof(Application))
                 {
                   _Application oWord = new Application();
                   oWord.DisplayAlerts = WdAlertLevel.wdAlertsNone;
                   t = (T)oWord;
                 }

                 if (t != null)
                 {
                     myQ.Enqueue(t);
                     iWordPoolInitialSize--;
                 }
            }
        }
        #endregion

        #region Public methods

        /// <summary>
        /// Method to get objects from pool
        /// </summary>
        /// <param name="asciiValue"></param>
        /// <returns></returns>
        public T GetObject()
        {
            T obj = default(T);
            if (myQ.Count > 0)
            {
                // Get it from the pool and return.
                obj = (T)myQ.Dequeue();
                //obj.AsciiValue = asciiValue;
            } /*else {
                // No items in pool give a new one..
                
                obj = (T) 
            }*/
            return obj;
        }

        /// <summary>
        /// Method to place it back in the pool. Syncronzied???
        /// </summary>
        /// <param name="obj"></param>
        public void Release(T obj)
        {
            if (obj != null)
            {
                // Store it in the pool for further use..
                myQ.Enqueue(obj);
            }
        }

        public void shutDownPool()
        {

            foreach (T obj in myQ)
            {
                _Application app = (_Application)obj;
                Object missing = System.Reflection.Missing.Value;
                app.Quit(ref missing, ref missing, ref missing);
            }

            myQ.Clear();
        }
        #endregion
    }
}

